﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Linq;

namespace Gmantis.Controls.Toolbar
{
    public class ToolbarGroupPanel : Panel
    {
        // Fields
        private List<CtrlGroup> _groups = new List<CtrlGroup>();
        private int nrows = 3;
        private bool useOldLayout;

        // Methods
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (this.useOldLayout)
            {
                return this.OldArrange(finalSize);
            }
            double x = 0.0;
            foreach (CtrlGroup group in this._groups)
            {
                double y = 0.0;
                for (int i = 0; i < group.Controls.Count; i++)
                {
                    double height = Math.Max(finalSize.Height, group.Size.Height);
                    UIElement element = group.Controls[i];
                    ToolbarControlSize local1 = group.Sizes[i];
                    if (group.Controls.Count == 1)
                    {
                        element.Arrange(new Rect(x, y, group.Size.Width, height));
                    }
                    else
                    {
                        element.Arrange(new Rect(x, y, group.Size.Width, element.DesiredSize.Height));
                    }
                    y += element.DesiredSize.Height;
                }
                x += group.Size.Width;
            }
            return finalSize;
        }

        private void CheckLayout()
        {
            this.useOldLayout = true;
            foreach (UIElement element in base.Children)
            {
                if (!(element is ToolbarStrip))
                {
                    this.useOldLayout = false;
                    break;
                }
            }
        }

        private static T FindParent<T>(DependencyObject child) where T : DependencyObject
        {
            DependencyObject parent = VisualTreeHelper.GetParent(child);
            if (parent == null)
            {
                return default(T);
            }
            T local = parent as T;
            if (local != null)
            {
                return local;
            }
            return FindParent<T>(parent);
        }

        private Collection<ToolbarGroupSizeDefinition> GetControlSizes()
        {
            ToolbarGroup group = FindParent<ToolbarGroup>(this);
            if (group != null)
            {
                return group.GroupSizeDefinitions;
            }
            if (base.Children.Count > 0)
            {
                FrameworkElement element = base.Children[0] as FrameworkElement;
                if (element != null)
                {
                    ToolbarGroup parent = element.Parent as ToolbarGroup;
                    if (parent != null)
                    {
                        return parent.GroupSizeDefinitions;
                    }
                }
            }
            return null;
        }

        private Size Measure(bool hasSizes, params ToolbarControlSize[] states)
        {
            Size size = new Size();
            int count = base.Children.Count;
            this._groups.Clear();
            if (count > 0)
            {
                CtrlGroup item = new CtrlGroup();
                ToolbarControlSize small = ToolbarControlSize.Small;
                for (int i = 0; i < count; i++)
                {
                    UIElement reference = base.Children[i];
                    ToolbarControlSize defaultControlSize = small;
                    if ((states != null) && (i < states.Length))
                    {
                        small = defaultControlSize = states[i];
                    }
                    if ((reference is ToolbarDropDown) && !hasSizes)
                    {
                        defaultControlSize = ((ToolbarDropDown)reference).GetDefaultControlSize();
                    }
                    if (reference is IToolbarControl)
                    {
                        ((IToolbarControl)reference).ChangeState(defaultControlSize.ToString());
                    }
                    reference.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                    if (!(reference is IToolbarControl) && (VisualTreeHelper.GetChildrenCount(reference) > 0))
                    {
                        DependencyObject child = VisualTreeHelper.GetChild(reference, 0);
                        if (child is IToolbarControl)
                        {
                            ((IToolbarControl)child).ChangeState(defaultControlSize.ToString());
                            reference.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                        }
                    }
                    if (defaultControlSize == ToolbarControlSize.Large)
                    {
                        if (item.Controls.Count > 0)
                        {
                            this._groups.Add(item);
                            item = new CtrlGroup();
                        }
                        item.Size = reference.DesiredSize;
                        item.Controls.Add(reference);
                        item.Sizes.Add(defaultControlSize);
                        this._groups.Add(item);
                        item = new CtrlGroup();
                    }
                    else
                    {
                        double width = Math.Max(item.Size.Width, reference.DesiredSize.Width);
                        double height = item.Size.Height + reference.DesiredSize.Height;
                        item.Size = new Size(width, height);
                        item.Controls.Add(reference);
                        item.Sizes.Add(defaultControlSize);
                        if (item.Controls.Count >= 3)
                        {
                            this._groups.Add(item);
                            item = new CtrlGroup();
                        }
                    }
                }
                if (item.Controls.Count > 0)
                {
                    this._groups.Add(item);
                }
                for (int j = 0; j < this._groups.Count; j++)
                {
                    size.Height = Math.Max(size.Height, this._groups[j].Size.Height);
                    size.Width += this._groups[j].Size.Width;
                }
                for (int k = 0; k < this._groups.Count; k++)
                {
                    this._groups[k].Size = new Size(this._groups[k].Size.Width, size.Height);
                }
            }
            return size;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            this.CheckLayout();
            if (this.useOldLayout)
            {
                return this.OldMeasure(availableSize);
            }
            Size size = new Size();
            Collection<ToolbarGroupSizeDefinition> controlSizes = this.GetControlSizes();
            if ((controlSizes != null) && (controlSizes.Count > 0))
            {
                foreach (ToolbarGroupSizeDefinition definition in controlSizes)
                {
                    if (definition.ControlSizes != null)
                    {
                        size = this.Measure(true, definition.ControlSizes.ToArray<ToolbarControlSize>());
                        if (size.Width <= availableSize.Width)
                        {
                            break;
                        }
                    }
                }
            }
            else
            {
                ToolbarControlSize[] states = new ToolbarControlSize[2];
                states[1] = ToolbarControlSize.Medium;
                size = this.Measure(false, states);
                if (size.Width > availableSize.Width)
                {
                    ToolbarControlSize[] sizeArray2 = new ToolbarControlSize[2];
                    sizeArray2[1] = ToolbarControlSize.Small;
                    size = this.Measure(false, sizeArray2);
                }
            }
            this.IsCollapsed = size.Width > availableSize.Width;
            return size;
        }

        private Size OldArrange(Size finalSize)
        {
            double x = 0.0;
            double y = 0.0;
            int count = base.Children.Count;
            double num4 = finalSize.Height / ((double)this.nrows);
            for (int i = 0; i < count; i++)
            {
                UIElement element = base.Children[i];
                Size desiredSize = element.DesiredSize;
                element.Arrange(new Rect(x, y, desiredSize.Width, desiredSize.Height));
                y += num4;
            }
            return finalSize;
        }

        private Size OldMeasure(Size availableSize)
        {
            int count = base.Children.Count;
            Size size = new Size();
            if (count > 0)
            {
                this.nrows = count;
                double num2 = (availableSize.Width * this.nrows) / ((double)count);
                double height = availableSize.Height / ((double)this.nrows);
                double num4 = 0.0;
                double num5 = 0.0;
                foreach (UIElement element in base.Children)
                {
                    element.Measure(new Size(double.PositiveInfinity, height));
                    if (!double.IsInfinity(availableSize.Width))
                    {
                        double width = availableSize.Width;
                        if (element.DesiredSize.Width > width)
                        {
                            element.Measure(new Size(width, height));
                        }
                        num5 = Math.Max(num5, element.DesiredSize.Width);
                    }
                    num4 = Math.Max(num4, element.DesiredSize.Width);
                    size.Width += element.DesiredSize.Width;
                    size.Height = Math.Max(size.Height, element.DesiredSize.Height);
                }
                size.Width = num5;
                size.Width = Math.Max(size.Width, num4);
                size.Height *= this.nrows;
            }
            return size;
        }

        // Properties
        internal bool IsCollapsed { get; private set; }

        // Nested Types
        private class CtrlGroup
        {
            // Fields
            private List<UIElement> _ctrls = new List<UIElement>();
            private List<ToolbarControlSize> _sizes = new List<ToolbarControlSize>();

            // Properties
            public List<UIElement> Controls
            {
                get
                {
                    return this._ctrls;
                }
            }

            public Size Size { get; set; }

            public List<ToolbarControlSize> Sizes
            {
                get
                {
                    return this._sizes;
                }
            }
        }
    }
}
